#include <pd_gpio.h>
#include <pd_i2c_hd.h>
#include <hd_oled_protocol_i2c.h>
#include <hd_oled.h>
#include <delay.h>
#include "main.h"


#define ARRAY_SIZE(x)       sizeof(x) / sizeof(x[0])
#define USE_HARDWARE_SPI    1
#define USE_HARDWARE_I2C    1
OLED oled;

uint8_t count = 0;

extern void SystemClock_Config(void);

void oled_instance(OLED *oled);

int main(void) {

    SystemClock_Config();

    NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);

    oled_instance(&oled);

    OLED_printf(&oled, 0, 0, "Standby Mode");
    OLED_refresh(&oled);

    // Enable PWR clock:
    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
    /**
     * PWR_CSR bit 8: EWUP, Enable WKUP pin
     *      0: WKUP pin is used for general purpose I/O.
     *      1: WKUP pin is used for wakeup from Standby mode and forced in input pull down
     *         configuration (rising edge on WKUP pin wakes-up the system from Standby mode)
     */
    LL_PWR_EnableWakeUpPin(LL_PWR_WAKEUP_PIN1);


    while (1) {
        OLED_printf(&oled, 0, 16, "Running");
        OLED_refresh(&oled);
        delay_ms(200);
        OLED_printf(&oled, 0, 16, "       ");
        OLED_refresh(&oled);
        delay_ms(200);

        OLED_printf(&oled, 0, 32, "Standby");
        OLED_refresh(&oled);
        delay_ms(1000);
        OLED_printf(&oled, 0, 32, "       ");
        OLED_refresh(&oled);
        delay_ms(200);

        OLED_clear(&oled);
        OLED_refresh(&oled);

        // Set Standby Mode
        // SCB_SCR SLEEPDEEP
        LL_LPM_EnableDeepSleep();
        /**
         * PWR_CR bit1: PDDS
         *     0: Enter Stop mode when the CPU enters deepsleep. The regulator status depends on the LPDS bit.
         *     1: Enter Standby mode when the CPU enters deepsleep.
         */
        LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY);
        /**
         * PWR_CR bit2: CWUF, Clear wakeup flag
         *      This bit is always read as 0.
         *      0: No effect
         *      1: Clear the WUF Wakeup Flag after 2 System clock cycles
         */
        LL_PWR_ClearFlag_WU();
        __WFI();

        // After the MCU is woken up from Standby mode, it will start running from the beginning of the main()
        // function, thus there is no need to re-initialize the clock.
    }

}


void oled_instance(OLED *oled) {
    // I2C gpio init
    static GPIO oledSckGPIO, oledSdaGPIO;
    GPIO_constructor(&oledSckGPIO, GPIOB, LL_GPIO_PIN_10); // I2Cx_SCK
    GPIO_constructor(&oledSdaGPIO, GPIOB, LL_GPIO_PIN_11); // I2Cx_SDA

#ifdef USE_HARDWARE_I2C
    static I2CHardware i2c2;
    I2CHardware_constructor(&i2c2, I2C2, &oledSckGPIO, &oledSdaGPIO);
#elif USE_SIMULATE_I2C
    static I2CSimulate i2c2;
    I2CSimulate_constructor(&i2c2, &oledSckGPIO, &oledSdaGPIO);
#endif
    I2C_init((I2C *) &i2c2);

    // OLED protocol of I2C
    static OLEDProtocolI2C oledProtocolI2c;
    OLEDProtocolI2C_constructor(&oledProtocolI2c, (I2C *) &i2c2);

    // OLED font instance.
    static OLEDFont oledFont;
    OLEDFont_contructor(&oledFont, NULL);

    // OLED instance of 4-PIN(I2C)
    OLED_constructor(oled, (OLEDProtocol *) &oledProtocolI2c, &oledFont);

    OLED_init(oled);

    OLED_clear(oled);
    OLED_refresh(oled);
}


